﻿// -------------------------------------------------------------------------
//    @FileName         :    NFMapUtil.cpp
//    @Author           :    gaoyi
//    @Date             :    24-8-30
//    @Email            :    445267987@qq.com
//    @Module           :    NFMapUtil
//
// -------------------------------------------------------------------------

#include "NFMapUtil.h"

#include <NFEventDisp.h>
#include <NFMapPart.h>
#include <NFPlayer.h>
#include <DescStore/CityMapDesc.h>

#include "NFMapModule.h"
#include "NFPacketSendUtil.h"
#include "NFPlayerUtil.h"
#include "NFTransMapMsg.h"

#include "proto_event.nanopb.h"
#include "proto_svr_map.nanopb.h"

NFMapPart* NFMapUtil::GetMapPart(NFPlayer* pPlayer)
{
    return pPlayer->GetPart<NFMapPart>();
}

const NFMapPart* NFMapUtil::GetMapPart(const NFPlayer* pPlayer)
{
    return pPlayer->GetPart<NFMapPart>();
}

int NFMapUtil::CheckEnterMap(NFPlayer* pPlayer, int iMapId)
{
    CHECK_NULL(0, pPlayer);
    auto pstCityMapDesc = CityMapDesc::Instance()->GetDesc(iMapId);
    CHECK_NULL(0, pstCityMapDesc);

    if (pstCityMapDesc->min_level > 0 && pPlayer->GetLevel() < pstCityMapDesc->min_level)
    {
        return proto_ff::ERR_CODE_MAP_ENTER_LEVEL_LIMIT;
    }

    if (pstCityMapDesc->max_level > 0 && pPlayer->GetLevel() > pstCityMapDesc->max_level)
    {
        return proto_ff::ERR_CODE_MAP_ENTER_LEVEL_LIMIT;
    }

    return 0;
}

int NFMapUtil::CheckAreaInfo(NFPlayer* pPlayer)
{
    CHECK_NULL(0, pPlayer);

    NFMapPart* pMapExt = pPlayer->GetPart<NFMapPart>();
    CHECK_NULL(0, pMapExt);

    const RoleMapData* pMapData = pMapExt->GetMapData();
    CHECK_NULL(0, pMapData);

    auto pDesc = CityMapDesc::Instance()->GetDesc(pMapData->map_desc_id);
    CHECK_NULL(0, pDesc);

    for (size_t i = 0; i < pDesc->area.size(); ++i)
    {
        if (pMapData->pos.x >= pDesc->area[i].min_x && pMapData->pos.x <= pDesc->area[i].max_x && pMapData->pos.z >= pDesc->area[i].min_z && pMapData->pos.z <= pDesc->area[i].max_z)
        {
            NFEventDisp::OnEnterArea(pPlayer, pMapData->map_desc_id, i);
            proto_ff::EventEnterArea eventData;
            eventData.set_map_desc_id(pMapData->map_desc_id);
            eventData.set_area_idx(i);
            FindModule<NFMapModule>()->FireExecute(NF_ST_LOGIC_SERVER, EVENT_ENTER_AREA, EVENT_SRC_TYPE_PLAYER, pPlayer->GetRoleID(), eventData);

            LOGSVR_DEBUG("player role id: " << pPlayer->GetRoleID() << " enter area: " << pMapData->map_desc_id << " area idx: " << i << " min x: " << pDesc->area[i].min_x << " max x: " << pDesc->area[i].max_x << " min z: " << pDesc->area[i].min_z << " max z: " << pDesc->area[i].max_z);
        }
    }

    return 0;
}

int NFMapUtil::CheckStartEnterMap(NFPlayer* pPlayer, const proto_ff::Proto_CSMapQueryReq& oCSReq)
{
    return 0;
}

int NFMapUtil::NeedEnterDefault(NFPlayer* pPlayer, int iMapId)
{
    CHECK_NULL(0, pPlayer);

    NFMapPart* pMapPart = GetMapPart(pPlayer);
    CHECK_NULL(pPlayer->GetRoleID(), pMapPart);

    RoleMapData* pMapData = pMapPart->GetMapData();
    CHECK_NULL(pPlayer->GetRoleID(), pMapData);

    if (pMapData->map_desc_id == iMapId && iMapId != DEFAULT_ENTER_CITY_MAP_ID)
    {
        LOG_INFO(pPlayer->GetRoleID(), "need enter default map:{}", iMapId);

        return StartEnterDefaultCity(pPlayer);
    }

    return 0;
}

int NFMapUtil::SynCityRoleInfo(NFPlayer* pPlayer, proto_ff::enCityRoleInfoChgReason enReason)
{
    return 0;
}

int NFMapUtil::StartEnterDefaultCity(NFPlayer* pPlayer)
{
    proto_ff::Proto_CSReq oCSReq;
    proto_ff::Proto_CSMapQueryReq *pMapQueryReq = oCSReq.mutable_map_query_req();
    pMapQueryReq->set_map_desc_id(DEFAULT_ENTER_CITY_MAP_ID);
    pMapQueryReq->set_trans_npc_id(0);
    return StartEnterMap(pPlayer, oCSReq);
}

int NFMapUtil::StartEnterMap(NFPlayer* pPlayer, const proto_ff::Proto_CSReq& csReq)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    const proto_ff::Proto_CSMapQueryReq& oCSMapQueryReq = csReq.map_query_req();
    iRetCode = CheckStartEnterMap(pPlayer, oCSMapQueryReq);
    if (iRetCode != 0)
    {
        NeedEnterDefault(pPlayer, oCSMapQueryReq.map_desc_id());
        return iRetCode;
    }

    NFTransMapMsg* pTrans = NFTransMapMsg::CreateTrans();
    CHECK_NULL_WF(pPlayer->GetRoleID(), pTrans, "NFTransMapMsg CreateTrans Failed");

    pTrans->Init(pPlayer, E_CS_MAP_QUERY_REQ, 0);

    iRetCode = pTrans->StartGCMapMsgReq(oCSMapQueryReq.map_desc_id(), csReq, nullptr);
    CHECK_ERR_AND_FIN_TRANS(iRetCode, pTrans, "StartGCMapMsgReq Failed");
    return 0;
}

int NFMapUtil::HandleGCMapMsgRsp(const proto_ff::Proto_GCMapMsgRsp& gcMapMsgRsp, const ExtraLevelEntrancePara& stData)
{
    int iRetCode = 0;
    switch (gcMapMsgRsp.rsp_data().type())
    {
        case EN_MAP_MSG_ENTER_MAP:
        {
            iRetCode = EnterMapRsp(gcMapMsgRsp, stData);
            break;
        }
        case EN_MAP_MSG_TRIGGER_BATTLE:
        {
            iRetCode = LeaveMapRsp(gcMapMsgRsp, stData);
            break;
        }
        default:
        {
            LOG_ERR(0, -1, "unhandle map msg type:{}", gcMapMsgRsp.rsp_data().type());
        }
    }
    return iRetCode;
}

int NFMapUtil::EnterMapRsp(const proto_ff::Proto_GCMapMsgRsp& gcMapMsgRsp, const ExtraLevelEntrancePara& stData)
{
    int iRetCode = 0;
    NFPlayer* pPlayer = NFPlayerUtil::GetPlayerByRoleID(gcMapMsgRsp.role_id());
    CHECK_NULL(gcMapMsgRsp.role_id(), pPlayer);

    int iEnterMapId = gcMapMsgRsp.cs_req().map_query_req().map_desc_id();

    NFMapPart* pMapPart = GetMapPart(pPlayer);
    CHECK_NULL(gcMapMsgRsp.role_id(), pMapPart);

    RoleMapData* pRoleMapData = pMapPart->GetMapData();
    int old_map_id = pRoleMapData->map_desc_id;
    if (pRoleMapData->map_desc_id != iEnterMapId || pPlayer->IsInBattle())
    {
        //StartLeaveMap(pPlayer, pRoleMapData->map_desc_id, proto_ff::EN_LEAVE_MAP_REASON_TRANSMAP);
    }

    //syn new map info
    iRetCode = HandleMapQuery(pPlayer, gcMapMsgRsp.rsp_data().map_obj_id(), gcMapMsgRsp.cs_req().map_query_req(), gcMapMsgRsp.rsp_data(), gcMapMsgRsp.rsp_data().token());
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "HandleMapQuery Failed");
    pMapPart->SetRoleObjID(gcMapMsgRsp.role_obj_id());
    return 0;
}

int NFMapUtil::LeaveMapRsp(const proto_ff::Proto_GCMapMsgRsp& gcMapMsgRsp, const ExtraLevelEntrancePara& stData)
{
    return 0;
}

int NFMapUtil::HandleMapQuery(NFPlayer* pPlayer, int iMapObjId, const proto_ff::Proto_CSMapQueryReq& oCSMapQueryReq, const proto_ff::GCMapMsgRspData& rspData, uint32_t iToken)
{
    CHECK_NULL(0, pPlayer);

    NFMapPart* pMapPart = GetMapPart(pPlayer);
    CHECK_NULL(pPlayer->GetRoleID(), pMapPart);

    if (!pPlayer->IsInBattle())
    {
        pMapPart->SetEnterCity(true);
    }

    //
    RoleMapData* pstRoleMapData = pMapPart->GetMapData();
    if (oCSMapQueryReq.map_desc_id() != pstRoleMapData->map_desc_id)
    {
        proto_ff::EventFinishLeaveCity eventLeaveCity;
        eventLeaveCity.set_map_desc_id(pstRoleMapData->map_desc_id);
        FindModule<NFMapModule>()->FireExecute(NF_ST_LOGIC_SERVER, EVENT_FINISH_LEAVE_CITY, EVENT_SRC_TYPE_PLAYER, pPlayer->GetRoleID(), eventLeaveCity);
    }

    proto_ff::EventFinishEnterCity eventEnterCity;
    eventEnterCity.set_map_desc_id(pstRoleMapData->map_desc_id);
    eventEnterCity.set_map_obj_id(iMapObjId);
    FindModule<NFMapModule>()->FireExecute(NF_ST_LOGIC_SERVER, EVENT_FINISH_ENTER_CITY, EVENT_SRC_TYPE_PLAYER, pPlayer->GetRoleID(), eventEnterCity);

    if (!pMapPart->FindEnterCity(oCSMapQueryReq.map_desc_id()))
    {
        pMapPart->AddEnterCity(oCSMapQueryReq.map_desc_id());
    }
    pMapPart->SynMapData(&rspData.map_data());

    //notify
    proto_ff::Proto_CSRsp oCSRsp;
    proto_ff::Proto_CSMapQueryRsp* pCSMapQueryRsp = oCSRsp.mutable_map_query_rsp();

    pCSMapQueryRsp->set_map_desc_id(oCSMapQueryReq.map_desc_id());
    pCSMapQueryRsp->set_index(0);
    pCSMapQueryRsp->set_map_obj_id(iMapObjId);
    pCSMapQueryRsp->set_token(iToken);

    auto pCityMapDesc = CityMapDesc::Instance()->GetDesc(oCSMapQueryReq.map_desc_id());
    CHECK_NULL_WF(pPlayer->GetRoleID(), pCityMapDesc, "get map desc:{} Failed!", oCSMapQueryReq.map_desc_id());

    pCSMapQueryRsp->set_map_svr_ip(rspData.ip());
    pCSMapQueryRsp->set_map_svr_port(rspData.port());
    pCSMapQueryRsp->set_map_svr_url(rspData.url());
    pMapPart->GetMapData()->ToPb(pCSMapQueryRsp->mutable_map_data());

    NFPacketSendUtil::SendToClient(pPlayer, E_CS_MAP_QUERY_RSP, &oCSRsp);
    return 0;
}
